package org.sky.framework.aop;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.sky.framework.exception.BusinessException;
import org.sky.framework.security.AuthEntity;
import org.sky.framework.security.AuthUtils;
import org.sky.framework.security.DigestSignature;
import org.sky.framework.util.ServletUtil;
import org.sky.framework.util.Utils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;

/**
 * 请求角色权限校验
 * 
 * @author gaofu
 *
 */
public class RoleAspect extends RequestAspect {
	@Value("${security.iauthorization.signature}")
	protected boolean iauthSign;
	@Value("${security.ignore.uri.regex}")
	protected String ingoreUriRegex;
	@Value("${security.default.roles}")
	protected String defaultRole;
	private DigestSignature digestSignature = null;

	/**
	 * 默认角色
	 */
	private volatile Collection<String> defaultRoles = null;
	private volatile Pattern ingorePattern = null;

	public RoleAspect(DigestSignature digestSignature) {
		this.digestSignature = digestSignature;
	}

	@Override
	protected void requestVerify(Class<?> targetClass, Method targetMethod) throws Exception {
		boolean isAnonymous = true;
		AuthEntity authEntity = new AuthEntity();
		HttpServletRequest request = ServletUtil.getRequest();
		try {
			String authinfo = request.getParameter(AuthUtils.Iauthorization);
			if (StringUtils.isEmpty(authinfo)) {
				authinfo = request.getHeader(AuthUtils.Iauthorization);
			}
			if (!StringUtils.isEmpty(authinfo)) {
				authEntity = decode(authinfo);
				request.setAttribute(AuthUtils.Iauthorization, authEntity);
				if (!StringUtils.isEmpty(authEntity.getUid())) {
					isAnonymous = false;
				}
			}
		} catch (Exception e) {
			logger.error("decode authVo error", e);
		}
		Annotation[] classAnnotations = targetClass.getAnnotations();
		Annotation[] methodAnnotations = targetMethod.getAnnotations();
		// 不是系统内部调用
		if (!AuthUtils.True.equals(authEntity.getIsd())) {
			// 匿名访问
			if (isAnonymous) {
				verifyAllowAnonymous(classAnnotations, methodAnnotations);
			} else {
				// 角色校验
				Collection<String> rolesAllowed = allowedRoles(classAnnotations, methodAnnotations);
				rolesAllowed.addAll(getDefaultRoles());
				if (!rolesAllowed.isEmpty()) {// 为空认为所有的角色都可以访问
					boolean denied = true;
					if (authEntity.getRls() != null) {
						for (String role : authEntity.getRls()) {
							if (rolesAllowed.contains(role)) {
								denied = false;
								break;
							}
						}
						if (denied) {
							throw accessDeniedException();
						}
					}
				}
			}
		}
	}

	/**
	 * 是否是忽略校权的资源
	 * 
	 * @param request
	 * @return
	 */
	protected boolean isIngoreUri(HttpServletRequest request) {
		boolean isIngore = false;
		if (getIngorePattern() != null) {
			String servletPath = request.getServletPath();
			isIngore = getIngorePattern().matcher(servletPath).find();
		}
		return isIngore;
	}

	/**
	 * 获取忽略url的正则表达式
	 * 
	 * @return
	 */
	protected Pattern getIngorePattern() {
		if (ingorePattern == null) {
			synchronized (this) {
				if (ingorePattern == null) {
					try {
						ingorePattern = Pattern.compile(ingoreUriRegex);
					} catch (Exception e) {
						logger.error("ingoreRegex Pattern compile error", e);
					}
				}
			}
		}
		return ingorePattern;
	}

	/**
	 * 摘要
	 * 
	 * @return
	 */
	protected DigestSignature getDigestSignature() {
		return digestSignature;
	}

	/**
	 * 获取默认角色
	 * 
	 * @return
	 */
	protected Collection<String> getDefaultRoles() {
		if (defaultRoles == null) {
			synchronized (this) {
				if (defaultRoles == null) {
					defaultRoles = new ArrayList<String>();
					if (!StringUtils.isEmpty(defaultRole)) {
						String[] roleArray = defaultRole.split(",");
						defaultRoles.addAll(Arrays.asList(roleArray));
					}
				}
			}
		}
		return defaultRoles;
	}

	/**
	 * 匿名访问校验
	 * 
	 * @param classAnnotations
	 * @param methodAnnotations
	 * @return
	 * @throws Exception
	 */
	protected void verifyAllowAnonymous(Annotation[] classAnnotations, Annotation[] methodAnnotations)
			throws Exception {
		// 匿名访问
		HttpServletRequest request = ServletUtil.getRequest();
		boolean isPermitAll = Utils.isPermitAll(classAnnotations) || Utils.isPermitAll(methodAnnotations);
		if (!isPermitAll && !isIngoreUri(request)) {
			throw accessDeniedException();
		}
	}

	/**
	 * 读取{@link javax.annotation.security.RolesAllowed} 注解的值
	 * 
	 * @param handler
	 * @return
	 */
	protected Collection<String> allowedRoles(Annotation[] classAnnotations, Annotation[] methodAnnotations) {
		List<String> roles = new ArrayList<>();
		Collection<String> methodRoles = Utils.allowedRoles(methodAnnotations);
		if (methodRoles != null && !methodRoles.isEmpty()) {
			roles.addAll(methodRoles);
		} else {
			Collection<String> classRoles = Utils.allowedRoles(methodAnnotations);
			if (classRoles != null && !classRoles.isEmpty()) {
				roles.addAll(classRoles);
			}
		}
		return roles;
	}

	/**
	 * 用户信息解码
	 * 
	 * @param userinfo
	 * @return
	 * @throws Exception
	 */
	protected AuthEntity decode(String userinfo) throws Exception {
		AuthEntity tokenVo = null;
		if (iauthSign) {
			tokenVo = digestSignatureDecode(userinfo);
		} else {
			tokenVo = gson.fromJson(userinfo, AuthEntity.class);
		}
		return tokenVo;
	}

	/**
	 * 用户信息解码
	 * 
	 * @param userinfo
	 * @return
	 * @throws Exception
	 */
	protected AuthEntity jsonDecode(String userinfo) throws Exception {
		return gson.fromJson(userinfo, AuthEntity.class);
	}

	/**
	 * 用户信息解码
	 * 
	 * @param userinfo
	 * @return
	 * @throws Exception
	 */
	protected AuthEntity digestSignatureDecode(String userinfo) throws Exception {
		return getDigestSignature().decode(userinfo, AuthEntity.class);
	}

	/**
	 * access denied Exception
	 * 
	 * @return
	 */
	protected Exception accessDeniedException() {
		return new BusinessException("access.denied");
	}

}
